﻿/*
 * Сделано в SharpDevelop.
 * Пользователь: max
 * Дата: 02.09.2012
 * Время: 18:43
 * 
 * Для изменения этого шаблона используйте Сервис | Настройка | Кодирование | Правка стандартных заголовков.
 */
using System;
using System.Windows.Data;
using System.Globalization;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using jellybird.core;
using System.Collections.Generic;
using System.Windows;


namespace jellybird
{

	public class MediaThumbToSizeConverter:IValueConverter
	{
		object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			/*
			 * value должно быть TwMediaInfo на входе
			 * parameter должен быть FrameworkElement с децствительными габаритами
			 * вернуть нужно BitmapImage
			 * 
			 */

			TwMediaInfo media_info = value as TwMediaInfo;
			if (media_info == null)
				return null;

			System.Windows.FrameworkElement thumbs_control = parameter as System.Windows.FrameworkElement;
			int max_width = (int)thumbs_control.ActualWidth;
//			int max_height=(int)thumbs_control.ActualHeight;
			int max_height=max_width;

			//media_element.PreferredWidth = desired_width;
			TwMediaThumbnail sel_thumb=media_info.SelectThumbnail(max_width,max_height);
			if(sel_thumb==null)
				return null;
			
			return TwMediaHelper.RetrieveImage(sel_thumb.ThumbnailUrl,sel_thumb.Width,sel_thumb.Height);
		}
		
		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotSupportedException();
		}
	}
	
	public class BoolToVisibiltyConverter:IValueConverter
	{
		object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			bool value_bool=(bool)value;
			if(value_bool)
			{
				return System.Windows.Visibility.Visible;
			}
			else
			{
				return System.Windows.Visibility.Collapsed;
			}
		}
		
		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotSupportedException();
		}
	}
	
	public class ContentOfunreadedButtonConverter:IValueConverter
	{
		object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			int value_int=(int)value;
			if(value_int==0)
				return string.Empty;
			else
				return string.Format("New tweets: {0}",value_int);
		}
		
		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotSupportedException();
		}
	}
	
	public class VisibiltyOfUnreadedButtonConverter:IValueConverter
	{
		object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			int value_int=(int)value;
			if(value_int==0)
				return System.Windows.Visibility.Collapsed;
			else
				return System.Windows.Visibility.Visible;
		}
		
		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotSupportedException();
		}
	}
	
	public class UnreadedTweetsConverter:IValueConverter
	{
		object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			int int_val=(int)value;
			return int_val==0?null:" ("+int_val.ToString()+")";
		}
		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotSupportedException();
		}
	}
	
	public class UserProfileUriConverter:IValueConverter
	{
		object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			return @"https://twitter.com/"+(string)value;
		}
		
		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotSupportedException();
		}
	}
	
	public class ScreenNameConverter:IValueConverter
	{
		object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			return '@'+(string)value;
		}
		
		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotSupportedException();
		}
	}
	
	public class BoolInversConverter:IValueConverter
	{
		object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			bool value_bool=(bool)value;
			return !value_bool;
		}
		
		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			bool value_bool=(bool)value;
			return !value_bool;
		}
	}
	
	public class DateTimeToStringConverter:IValueConverter
	{
		/*
		 * http://msdn.microsoft.com/en-US/library/az4se3k1.aspx
		 */
		
		object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			DateTime dt = (DateTime)value;
			DateTime now=DateTime.Now;
			string format=string.Empty;
			
			if(dt.Date==now.Date)
			{
				format="T";
			}
			else
			{
				format="G";
			}
			
			
			return dt.ToString(format,culture);
//			return culture.DisplayName;
		}
		
		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotSupportedException();
		}
	}
	
	/// <summary>
	/// Description of ValueConvertors.
	/// </summary>
	public class TweetToSpanConverter:IValueConverter
	{
		
		/*
		 * В кновертер передаётся культура
		 * наследуемая от окна,
		 * а не культура из потока
		 * 
		 * TODO: попадаются html entities типа '@amp;', их надо как то обходить
		 * ибо Json конвертер их оставляет как есть
		 */
		
		private string m_Format_Hashtag;
		public string FormatHashtag
		{
			get
			{
				return m_Format_Hashtag;
			}
			set
			{
				if(value==m_Format_Hashtag)
					return;
				
				if(string.IsNullOrWhiteSpace(value))
				{
					return;
				}
				
				m_Format_Hashtag=value;
			}
		}
		
		string m_FormatUserName;
		
		public string FormatUserName
		{
			get { return m_FormatUserName; }
			set
			{
				if(value==m_Format_Hashtag)
					return;
				if(string.IsNullOrWhiteSpace(value))
					return;
				
				m_FormatUserName = value;
			}
		}
		
		string m_FormatMention;
		
		public string FormatMention
		{
			get { return m_FormatMention; }
			set
			{
				if(value==m_FormatMention)
					return;
				if(string.IsNullOrWhiteSpace(value))
					return;
				
				m_FormatMention = value;
			}
		}
		
		public TweetToSpanConverter()
		{
			TargetType=typeof(Span);
			FormatHashtag="#{0}";
			FormatUserName="@{0}";
			FormatMention="@{0}";
		}
		
		public static Type TargetType{get;private set;}
		
		object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if(targetType==null)
				throw new ArgumentNullException("targetType");
			if((targetType!=TargetType)&&(!targetType.IsSubclassOf(TargetType)))
				throw new InvalidCastException("Only Span type supported");

			if (value == null) return null;

			TwTweet tweet=value as TwTweet;
			if(tweet==null)
				throw new InvalidCastException("Only TwTweet type supported");
			
			//Actual convert here
			List<SpanRange> range_list=create_ranges_intern(tweet);
			Span ret=create_span_from_ranges(tweet,range_list,culture);
			
			return ret;
		}
		
		private Span create_span_from_ranges(TwTweet tweet,List<SpanRange> ranges,CultureInfo culture_info)
		{
			Span ret=new Span();
			
			foreach (var range in ranges)
			{
				if(range.Tag==null)
				{
					//range - это простой текст
					Run run_basic=new Run()
					{
						Text=range.Length==tweet.TextOriginal.Length?
							tweet.TextOriginal:
							tweet.TextOriginal.Substring(range.Offset,range.Length)
					};
					ret.Inlines.Add(run_basic);

					continue;
				}
				
				TwEntityHashtag hashtag=range.Tag as TwEntityHashtag;
				if(hashtag!=null)
				{
					//это хештэг #blabla
					Run run_hashtag=new Run()
					{
						Text=string.Format(culture_info,FormatHashtag,hashtag.Text)
							//here add custom style
					};
					Hyperlink hl = new Hyperlink(run_hashtag);

					ret.Inlines.Add(hl);
					continue;
				}
				
				TwEntityMedia media=range.Tag as TwEntityMedia;
				if(media!=null)
				{
					Hyperlink hl_media = new Hyperlink(new Run(media.DisplayUrl))
					{
						Command = MyCommands.NavigateUrl,
						NavigateUri = new Uri(media.MediaUrl, UriKind.Absolute)
					};
					ret.Inlines.Add(hl_media);
					//TODO может здесь и сразу привязать к щелчку - не надо
					//или в тег записать объект media
					continue;
				}
				
				TwEntityUrl url=range.Tag as TwEntityUrl;
				if(url!=null)
				{
					Hyperlink hl_url = new Hyperlink(new Run(url.DislayUrl))
					{
						Command = MyCommands.NavigateUrl,
						NavigateUri = new Uri(url.ExpandedUrl, UriKind.Absolute)
					};
					ret.Inlines.Add(hl_url);
					continue;
				}
				
				TwEntityUserMention mention=range.Tag as TwEntityUserMention;
				if(mention!=null)
				{
					Hyperlink hl_mention = new Hyperlink(new Run(string.Format(culture_info, FormatMention, mention.DisplayName)))
					{
						Command = MyCommands.NavigateUrl,
						NavigateUri = new Uri(@"https://twitter.com/" + mention.DisplayName, UriKind.Absolute)
					};
					
					ret.Inlines.Add(hl_mention);
					continue;
				}
			}
			
			return ret;
		}
		
		private List<SpanRange> create_ranges_intern(TwTweet tweet)
		{
			List<SpanRange> ret=new List<TweetToSpanConverter.SpanRange>();
			SpanRange init_range=new TweetToSpanConverter.SpanRange()
			{
				Tag=null,
				Offset=0,
				Length=tweet.TextOriginal.Length
			};
			ret.Add(init_range);
			
			
			if(tweet.EntitiesOriginal!=null)
			{
				if(tweet.EntitiesOriginal.Hashtags!=null)
				{
					foreach(var ent in tweet.EntitiesOriginal.Hashtags)
					{
						SpanRange range_hash=new TweetToSpanConverter.SpanRange()
						{
							Tag=ent,
							Offset=ent.Indices[0],
							Length=ent.Indices[1]-ent.Indices[0]
						};
						insert_range_intern(ret,range_hash);
					}
				}
				
				if(tweet.EntitiesOriginal.Media!=null)
				{
					foreach(var ent in tweet.EntitiesOriginal.Media)
					{
						SpanRange range_media=new TweetToSpanConverter.SpanRange()
						{
							Tag=ent,
							Offset=ent.Indices[0],
							Length=ent.Indices[1]-ent.Indices[0]
						};
						insert_range_intern(ret,range_media);
					}
				}
				
				if(tweet.EntitiesOriginal.Urls!=null)
				{
					foreach(var ent in tweet.EntitiesOriginal.Urls)
					{
						SpanRange range_url=new TweetToSpanConverter.SpanRange()
						{
							Tag=ent,
							Offset=ent.Indices[0],
							Length=ent.Indices[1]-ent.Indices[0]
						};
						insert_range_intern(ret,range_url);
					}
				}
				
				if(tweet.EntitiesOriginal.UserMentions!=null)
				{
					foreach(var ent in tweet.EntitiesOriginal.UserMentions)
					{
						SpanRange range_mnem=new TweetToSpanConverter.SpanRange()
						{
							Tag=ent,
							Offset=ent.Indices[0],
							Length=ent.Indices[1]-ent.Indices[0]
						};
						insert_range_intern(ret,range_mnem);
					}
				}
			}
			
			return ret;
		}
		
		private void insert_range_intern(List<SpanRange> list,SpanRange range)
		{
			//куда вставляем?
			int target_ind=-1;
			for(int i=0;i<list.Count;i++)
			{
				if(range.Offset<=list[i].Length+list[i].Offset)
				{
					target_ind=i;
					break;
				}
			}
			
			if(target_ind==-1)
				throw new ArgumentException();
			
			if(list[target_ind].Offset==range.Offset)
			{
				if(list[target_ind].Length==range.Length)
				{
					list[target_ind]=range;
				}
				else
				{
					//пересечений быть не должно
					list[target_ind].Offset=range.Offset+range.Length;
					list[target_ind].Length=list[target_ind].Length-range.Length;
					list.Insert(target_ind,range);
				}
			}
			else
			{
				if(list[target_ind].Offset+list[target_ind].Length==range.Offset+range.Length)
				{
					//конец сопадает
					list[target_ind].Length=range.Offset-list[target_ind].Offset;
					list.Insert(target_ind+1,range);
				}
				else
				{
					//ни конец ни начало не сопадают
					//нужно раздоить list[target_ind]
					int orig_len=list[target_ind].Length;
					list[target_ind].Length=range.Offset-list[target_ind].Offset;
					SpanRange range_tail=new TweetToSpanConverter.SpanRange
					{
						Tag=list[target_ind].Tag,
						Offset=range.Offset+range.Length,
						Length=orig_len-range.Length-list[target_ind].Length
					};
					//вставляем в таком порядке чтобы не попутать индексы
					list.Insert(target_ind+1,range);
					//и хвост
					list.Insert(target_ind+2,range_tail);
				}
			}
		}
		
		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotSupportedException("Cannot convert from span to tweet object");
		}
		
		private class SpanRange
		{
			internal int Offset;
			internal int Length;
			internal object Tag;
		}
	}
}
